package com.ruoyi.life.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.SecurityUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.bean.BeanUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.life.domain.EnterpriseWithCode;
import com.ruoyi.life.domain.FeMeterBill;
import com.ruoyi.life.domain.FeStandard;
import com.ruoyi.life.domain.vo.MonthShareVO;
import com.ruoyi.life.mapper.FeStandardMapper;
import com.ruoyi.life.service.IFeBillService;
import com.ruoyi.life.service.IFeMeterBillService;
import com.ruoyi.life.service.IFeStandardService;
import com.ruoyi.omp.api.RemoteCheckMeterService;
import com.ruoyi.omp.api.domain.FeBill;
import com.ruoyi.omp.api.domain.NyCheckMeter;
import com.ruoyi.omp.api.domain.NyMeterAccount;
import com.ruoyi.omp.api.domain.vo.EnterpriseVo;
import com.ruoyi.omp.api.domain.vo.NyCheckMeterVO;
import com.ruoyi.omp.api.enums.FeeTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.dao.DataAccessException;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 水电收费标准Service业务层处理
 *
 * @author cjie
 * @date 2021-11-06
 */
@Slf4j
@Service
public class FeStandardServiceImpl implements IFeStandardService {
    @Autowired
    private FeStandardMapper feStandardMapper;
    @Autowired
    private RemoteCheckMeterService remoteCheckMeterService;
    @Autowired
    private IFeBillService feBillService;
    @Autowired
    private IFeMeterBillService feMeterBillService;

    /**
     * 查询水电收费标准
     *
     * @param id 水电收费标准ID
     * @return 水电收费标准
     */
    @Override
    public FeStandard selectFeStandardById(String id) {
        FeStandard feStandard = feStandardMapper.selectFeStandardById(id);
        NyCheckMeter queryCheckMeter = new NyCheckMeter();
        queryCheckMeter.setFeeCycle(feStandard.getFeeCycle());
        queryCheckMeter.setParkNum(feStandard.getParkNum());
        queryCheckMeter.setMeterType("水表");
        List<MonthShareVO> waterNyCheckMeterVOS = listTotalCheckMater(queryCheckMeter);
        feStandard.setWMonthShareVOList(waterNyCheckMeterVOS);

        queryCheckMeter.setMeterType("电表");
        List<MonthShareVO> elNyCheckMeterVOS = listTotalCheckMater(queryCheckMeter);
        feStandard.setElMonthShareVOList(elNyCheckMeterVOS);
        //listTotalCheckMater(queryCheckMeter).getData();
        //feStandard.setCheckMeterVOList();
        return feStandard;
    }

    /**
     * 查询水电收费标准列表
     *
     * @param feStandard 水电收费标准
     * @return 水电收费标准
     */
    @Override
    public List<FeStandard> selectFeStandardList(FeStandard feStandard) {
        return feStandardMapper.selectFeStandardList(feStandard);
    }

    /**
     * 新增水电收费标准,todo 事务
     *
     * @param feStandard 水电收费标准
     * @return 结果
     */
    @Transactional
    @Override
    public AjaxResult insertFeStandard(FeStandard feStandard) {
        feStandard.setId(IdUtil.getSnowflake(0, 0).nextIdStr());
        feStandard.setCreateTime(DateUtils.getNowDate());
        feStandard.setCreateBy(SecurityUtils.getUsername());
        int rows = 0;
        try{
            rows = feStandardMapper.insertFeStandard(feStandard);
        }catch (DataAccessException e){
            return AjaxResult.error("新增失败！水电标准已存在");
        }

        setMonthShare(feStandard);
        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
    }

    /**
     * 设定每月的分摊值
     *
     * @param feStandard 费用标准
     */
    private void setMonthShare(FeStandard feStandard) {
        //todo 修改 分摊池，
        //设定总表分摊池，
        if (feStandard.getElMonthShareVOList() != null) {
            feStandard.getElMonthShareVOList().forEach(checkMeterVO -> {
                //查询抄表记录
                if(StringUtils.isNotEmpty(checkMeterVO.getCheckMaterId())){
                    R<NyCheckMeter> r = remoteCheckMeterService.getCheckMeter(checkMeterVO.getCheckMaterId());
                    if (r.getCode() == HttpStatus.SUCCESS) {
                        //r.getData 为空
                        NyCheckMeter nyCheckMeter = r.getData();
                        nyCheckMeter.setMonthShare(checkMeterVO.getMonthShare());
                        BigDecimal residualQuantity = checkMeterVO.getShareInitialValue().subtract(checkMeterVO.getMonthShare());
                        nyCheckMeter.setShareInitialValue(residualQuantity);
                        remoteCheckMeterService.updateCheckMeter(nyCheckMeter);
                        //剩余量 更新有误会，总表数据没有抄录；

//                        NyMeterAccount nyMeterAccount = new NyMeterAccount();
//                        nyMeterAccount.setId(checkMeterVO.getMeterId());
//                        nyMeterAccount.setShareInitialValue(residualQuantity);
//                        remoteCheckMeterService.updateNyMeterAccount(nyMeterAccount);
                    }
                }else{
                    log.error("设置分摊池失败" + checkMeterVO.getMeterName() + " " + checkMeterVO.getMeterNum() + " " + feStandard.getFeeCycle() +"未抄录");
                }
            });
        }

        //设定总表分摊值，更新分摊池
        if (feStandard.getWMonthShareVOList() != null) {
            feStandard.getWMonthShareVOList().forEach(checkMeterVO -> {
                //查询抄表记录
                if(StringUtils.isNotEmpty(checkMeterVO.getCheckMaterId())){
                    R<NyCheckMeter> r = remoteCheckMeterService.getCheckMeter(checkMeterVO.getCheckMaterId());
                    if (r.getCode() == HttpStatus.SUCCESS) {
                        //r.getData 为空
                        NyCheckMeter nyCheckMeter = r.getData();
                        nyCheckMeter.setMonthShare(checkMeterVO.getMonthShare());
                        BigDecimal residualQuantity = checkMeterVO.getShareInitialValue().subtract(checkMeterVO.getMonthShare());
                        nyCheckMeter.setShareInitialValue(residualQuantity);
                        remoteCheckMeterService.updateCheckMeter(nyCheckMeter);
                        //剩余量 更新有误会，总表数据没有抄录；

                    }
                }else{
                    log.error("设置分摊池失败" + checkMeterVO.getMeterName() + " " + checkMeterVO.getMeterNum() + " " + feStandard.getFeeCycle() +"未抄录");
                }
            });
        }
    }

    /**
     * 修改水电收费标准 todo 事务
     *
     * @param feStandard 水电收费标准
     * @return 结果
     */
    @Override
    public int updateFeStandard(FeStandard feStandard) {
        feStandard.setUpdateTime(DateUtils.getNowDate());
        feStandard.setUpdateBy(SecurityUtils.getUsername());

        setMonthShare(feStandard);
        return feStandardMapper.updateFeStandard(feStandard);
    }

    /**
     * 批量删除水电收费标准
     *
     * @param ids 需要删除的水电收费标准ID
     * @return 结果
     */
    @Override
    public int deleteFeStandardByIds(String[] ids) {
        return feStandardMapper.deleteFeStandardByIds(ids);
    }

    /**
     * 删除水电收费标准信息
     *
     * @param id 水电收费标准ID
     * @return 结果
     */
    @Override
    public int deleteFeStandardById(String id) {
        return feStandardMapper.deleteFeStandardById(id);
    }

    /**
     * 查询总表抄表记录,
     *
     * @param nyCheckMeter
     * @return
     */
    @Override
    public List<MonthShareVO> listTotalCheckMater(NyCheckMeter nyCheckMeter) {
        List<MonthShareVO> result = new ArrayList<MonthShareVO>();
        R<List<NyCheckMeterVO>> r = remoteCheckMeterService.listCheckMonthShare(nyCheckMeter);
        if (r.getCode() == HttpStatus.SUCCESS) {

            //NyCheckMeter to List<MonthShareVO>
            for(NyCheckMeterVO nyCheckMeterVO:r.getData()){
                MonthShareVO monthShareVO = new MonthShareVO();
                monthShareVO.setCheckMaterId(nyCheckMeterVO.getCheckMaterId());
                monthShareVO.setMeterNum(nyCheckMeterVO.getMeterNum());
                monthShareVO.setMeterName(nyCheckMeterVO.getMeterName());
                monthShareVO.setMeterId(nyCheckMeterVO.getMeterId());
                if(nyCheckMeterVO.getMonthShare() == null){
                    monthShareVO.setMonthShare(BigDecimal.ZERO);
                }else {
                    monthShareVO.setMonthShare(nyCheckMeterVO.getMonthShare());
                }

                monthShareVO.setShareInitialValue(nyCheckMeterVO.getShareInitialValue());
                result.add(monthShareVO);
            }
        }

        return result;
    }

    /**
     * 根据billNum生成总账单
     * @param billNum
     */
    public int createRealFeeBill(String billNum){
        FeMeterBill queryFeMeterBill=new FeMeterBill();
        queryFeMeterBill.setBillNum(billNum);
        List<FeMeterBill> feMeterBills = feMeterBillService.selectFeMeterBillList(queryFeMeterBill);
        BigDecimal allTotalAmount = feMeterBills.stream() .map(FeMeterBill::getTotalAmount).reduce(BigDecimal.ZERO,BigDecimal::add);
        FeBill feBill=new FeBill();
        if (feMeterBills.size()>0){
            FeMeterBill rFeMeterBill =feMeterBills.get(0);
            BeanUtils.copyBeanProp(feBill,rFeMeterBill);
            if(StringUtils.isEmpty(rFeMeterBill.getEnterpriseId())){
                R  r = remoteCheckMeterService.getEenterpriseByName(rFeMeterBill.getEnterpriseName());
                rFeMeterBill.setEnterpriseId(r.getData().toString());
            }
            R<EnterpriseVo> r=remoteCheckMeterService.getEenterprise(rFeMeterBill.getEnterpriseId());
            EnterpriseVo enterpriseVo=r.getData();
            feBill.setEnterpriseName(enterpriseVo.getEnterpriseName());
            feBill.setGarbageFee(enterpriseVo.getGarbageFee());
            feBill.setSewageFee(enterpriseVo.getSewageFee());
            feBill.setElevatorRunFee(enterpriseVo.getElevatorRunFee());
            feBill.setElevatorRepairFee(enterpriseVo.getElevatorRepairFee());
            feBill.setEnterpriseId(rFeMeterBill.getEnterpriseId());
            feBill.setFeeType(FeeTypeEnum.WATERELANDEl.getCode());
            if(feBill.getGarbageFee() != null){
                allTotalAmount = allTotalAmount.add(feBill.getGarbageFee());
            }
            if(feBill.getSewageFee() != null){
                allTotalAmount = allTotalAmount.add(feBill.getSewageFee());
            }

            feBill.setReceivableAmount(allTotalAmount);

            feBillService.insertFeBill(feBill);
            return 1;
        }else {
            return 0;
        }
    }

    /**
     * 创建水电费账单
     *
     * @param id 标准id
     * @return
     */
    @Override
    public AjaxResult createFeeBill(String id) {
        FeStandard feStandard = feStandardMapper.selectFeStandardById(id);
        NyCheckMeter queryCheckMeter = new NyCheckMeter();
        queryCheckMeter.setFeeCycle(feStandard.getFeeCycle());
        queryCheckMeter.setParkNum(feStandard.getParkNum());
        R<List<NyCheckMeterVO>> r = remoteCheckMeterService.listCheckMeter(queryCheckMeter);
        if (r.getCode() == HttpStatus.SUCCESS) {
            //总表
            List<NyCheckMeterVO> nyCheckMeterVOS = r.getData();
            //暂存私表企业的所有id
            List<String> enNames = new ArrayList<>();
            //遍历总表获取childrenList的企业
            nyCheckMeterVOS.forEach(nyCheckMeterVO -> {
                List<NyCheckMeterVO> childrenList = nyCheckMeterVO.getChildren();
                if (childrenList == null || childrenList.size() == 0) {
                    return;
                }
                List<String> enterpriseChildNames = childrenList.stream().map(NyCheckMeterVO::getEnterpriseName).collect(Collectors.toList());
                enNames.addAll(enterpriseChildNames);
            });
            //去重获取的企业id集合
            List<String> enterpriseNames = enNames.stream().distinct().collect(Collectors.toList());
            //企业对应账单号list
            List<EnterpriseWithCode> enterpriseWithCodes = new ArrayList<>();
            //创建企业对应账单号，以生成账单
            enterpriseNames.forEach(enterpriseName -> {
                EnterpriseWithCode enterpriseWithCode = new EnterpriseWithCode();
                enterpriseWithCode.setEnterpriseName(enterpriseName);
                enterpriseWithCode.setBillCode(IdUtil.getSnowflake(0, 0).nextIdStr());
                enterpriseWithCodes.add(enterpriseWithCode);
            });
            for(NyCheckMeterVO nyCheckMeterVO:nyCheckMeterVOS){
                if(nyCheckMeterVO.getCheckMaterId().isEmpty()){
                    log.info(nyCheckMeterVO.getMeterNum() +" " + nyCheckMeterVO.getMeterName() + " " + nyCheckMeterVO.getCategory() +" " + DateUtils.parseDateToStr(DateUtils.YYYY_MM,nyCheckMeterVO.getFeeCycle()) +" 未抄录");
                    continue;
                }
                //获取私表记录
                List<NyCheckMeterVO> childrenList = nyCheckMeterVO.getChildren();
                if (childrenList == null || childrenList.isEmpty()) {
                    continue;
                }
                //该总表下的所有分表用量总和,用于计算分摊系数
                //BigDecimal fenAllQuantity = childrenList.stream() .map(NyCheckMeterVO::getActualDosage).reduce(BigDecimal.ZERO,BigDecimal::add);
                BigDecimal fenAllQuantity = BigDecimal.ZERO;
                for(NyCheckMeterVO child:childrenList){
                    if(child.getCheckMaterId().isEmpty()){
                        log.info(child.getMeterNum() +" " + child.getEnterpriseName() + " " + child.getCategory() +" " + DateUtils.parseDateToStr(DateUtils.YYYY_MM,child.getFeeCycle()) +" 未抄录");
                        continue;
                    }
                    fenAllQuantity = fenAllQuantity.add(child.getActualDosage());
                }

                //开始计算账单
                for(NyCheckMeterVO childMeter:childrenList){
                    //判断是否有抄表记录，如果有抄表记录在生成账单
                    if (StringUtils.isNotEmpty(childMeter.getCheckMaterId())) {
                        List<EnterpriseWithCode> enWithBill=enterpriseWithCodes.stream().filter(enterpriseWithCode->enterpriseWithCode.getEnterpriseName().equals(childMeter.getEnterpriseName())).collect(Collectors.toList());
                        FeMeterBill feMeterBill = new FeMeterBill();
                        feMeterBill.setCheckMeterId(childMeter.getCheckMaterId());
                        feMeterBill.setEnterpriseId(childMeter.getEnterpriseId());
                        feMeterBill.setEnterpriseName(childMeter.getEnterpriseName());
                        feMeterBill.setMeterType(childMeter.getMeterType());
                        feMeterBill.setFeeCycle(childMeter.getFeeCycle());
                        feMeterBill.setParkId(feStandard.getParkId());
                        feMeterBill.setActualDosage(childMeter.getActualDosage());
                        feMeterBill.setMeterId(childMeter.getMeterId());
                        feMeterBill.setBeginDate(DateUtil.date());
                        feMeterBill.setBillNum(enWithBill.get(0).getBillCode());
                        feMeterBill.setLastValue(childMeter.getLastValue());
                        feMeterBill.setCurrentValue(childMeter.getCurrentValue());
                        feMeterBill.setMeterNum(childMeter.getMeterNum());
                        feMeterBill.setMagnification(childMeter.getMagnification());
                        //BeanUtils.copyBeanProp(feMeterBill,childMeter);
                        if ("水表".equals(childMeter.getMeterType())) {
                            feMeterBill.setUnitPrice(feStandard.getWaterUnitPrice());
                        } else if ("电表".equals(childMeter.getMeterType())) {
                            //电费乘以倍率
                            BigDecimal uPrice=feStandard.getElUnitPrice().setScale(2, RoundingMode.HALF_UP);
                            feMeterBill.setUnitPrice(uPrice);
                        }
                        if (feMeterBill.getActualDosage() != null && feMeterBill.getUnitPrice() != null) {
                            feMeterBill.setFeeAmount(feMeterBill.getActualDosage().multiply(feMeterBill.getUnitPrice()).setScale(2, RoundingMode.HALF_UP));
                        }
                        if (childMeter.getActualDosage() != null && (nyCheckMeterVO.getActualDosage() != null) && nyCheckMeterVO.getMonthShare() != null) {
                            //分摊系数=分表读数/分表总和
                            feMeterBill.setShareCoefficient(childMeter.getActualDosage().divide(fenAllQuantity, 20, RoundingMode.HALF_UP));
                            feMeterBill.setShareQuantity(nyCheckMeterVO.getMonthShare().multiply(feMeterBill.getShareCoefficient()).setScale(2, RoundingMode.HALF_UP));
                           //电表金额应该乘以倍率
                            if ("水表".equals(childMeter.getMeterType())){
                                feMeterBill.setShareAmount(feMeterBill.getShareQuantity().multiply(feMeterBill.getUnitPrice()).setScale(2, RoundingMode.HALF_UP));
                            }else  if ("电表".equals(childMeter.getMeterType())){
                                feMeterBill.setShareAmount(feMeterBill.getShareQuantity().multiply(feMeterBill.getUnitPrice()).setScale(2, RoundingMode.HALF_UP).multiply(childMeter.getMagnification()));
                            }

                            StringBuilder stringBuilder = new StringBuilder("应收金额=");
                            feMeterBill.setTotalAmount(feMeterBill.getFeeAmount().add(feMeterBill.getShareAmount()));
                            stringBuilder.append(feMeterBill.getFeeAmount()).append("(读数金额) + ")
                                    .append(feMeterBill.getShareAmount())
                                    .append("(分摊金额) = ")
                                    .append(feMeterBill.getShareAmount());
                            feMeterBill.setRemark(stringBuilder.toString());
                        }
                        //插入子账单
                        feMeterBillService.insertFeMeterBill(feMeterBill);
                    }

                };
            };
            //生成总账单
            enterpriseWithCodes.forEach(enpr->{
                this.createRealFeeBill(enpr.getBillCode());
            });

        } else {
            return AjaxResult.error(r.getMsg());
        }
        return AjaxResult.success();
    }
}
